package kaixo12;




import kaixo12.*;

import com.ibm.saguaro.system.*;


public class Kaixo { 
	static long xmitDelay2;
	//LEds
	static Timer timerLEds;
    // time interval in ticks for toggleing a LED
    static long INTERVALLEDS;
    // LED index
    static byte idxLeds;
    //Leds
    static byte ledRojo=0;
    static byte ledAmarillo=0;
    static byte ledVerde=0;
    
    // the number of LEDs for the platform
    static int numLeds;
    // blink object required for the delegate callback
    //static Kaixo blink;
	
	//informacion Ruta para el IDS
	static int idsId=2;
	static int[] nora = {1,2,3,4,5};
	static int[] nundik = {1,2,3,3,3};
	static Nodo[] red;
	
	
	static int pak=0;
	//Informacion conexiones IDS
	static int[] conexionRealizada;
	static int[] conexionFallida;
	static int[] conexionNodo;
	static int[] estadoConexion;
	static int[] estadoNodo;
	
	//flags IDS
	static boolean ack=false;
	static boolean esperandoAck=false;
	static boolean enviado=false;
	static boolean listo=true;
	
	//Comunicaciones
	static Comunicaciones conection;
	
	//timers
	
	static Timer timer;
	
	//moterunnes
	static Kaixo rcount;
	static Timer tsend;
	static int i=0;
	static byte[] xmit;
	static long xmitDelay;
    static RadioTxDone onDone;
    // time interval in ticks for toggleing a LED
    static long INTERVAL;  
      
	static {
		//configura Leds
		idxLeds = 0;
		// get the number of LEDs
        numLeds = LED.getNumLEDs();
        // turn off all LEDs initially
    	//allLedsOff();

        // initialize object required for callback
       // blink = new Kaixo();
		
		//Termina configurar Leds
		rcount = new Kaixo();	
		
		// Crear Comunicaciones
		conection = new Comunicaciones(idsId,nora,nundik);
		//Crear Nodos
		red = new Nodo[10];
		red[0] = new Nodo(1,1);
		red[1] = new Nodo(2,2);
		red[2] = new Nodo(3,3);
		red[1] = new Nodo(4,3);
		red[2] = new Nodo(5,3);
		/*
		// acquire radio device
		Radio.acquire();
		
		// set the PAN ID to 0x22 and the short address 
		// to the last two bytes of the extended address
		Radio.setPanId(0x22, true);
		byte[] myAddrBytes = new byte[8];
		Radio.getExtAddr(myAddrBytes , 0);
		Radio.setShortAddr(Util.get16le(myAddrBytes, 0));
		*/

		// prepare beacon frame with src addressing
		xmit = new byte[12];
        xmit[0] = Radio.FCF_BEACON;
		xmit[1] = Radio.FCA_SRC_SADDR;
        Util.set16le(xmit, 3, 0x22);
		Util.set16le(xmit, 5, 0x1234);
                
            onDone = new RadioTxDone(null) {
			public void invoke(byte[] pdu, int len, int status, long txend) {
				Kaixo.transmitDone(pdu,len,status,txend);
			}
		};

		// put radio into receive mode on channel 0
		Radio.setRxHandler((byte)0, new RadioRxPdu(null){
			public void invoke(byte[] pdu, int len, long time, int quality){
				Kaixo.onRxPDU(pdu, len, time, quality);
			}
		});

		Radio.setRxDone(new RadioDone (null) {
			public void invoke (int info) { 
				Kaixo.onRxTimeout(info);
			}
		});

		Radio.enableRx(Time.currentTicks()+0x7FFFFFFF);

		// setup a periodic timer callback
		tsend = new Timer();
		tsend.setCallback(new TimerEvent(null){
			public void invoke(byte param, long time){			
				Kaixo.periodicSend(param, time);
			}
		});
		// convert the periodic delay from ms to platform ticks
		xmitDelay = Time.toTickSpan(Time.SECONDS, 5);
		// Start the timer
		tsend.setAlarmBySpan(xmitDelay);
		
		
		timerLEds = new Timer();
		timerLEds.setCallback(new TimerEvent(null){
			public void invoke(byte param, long time){
				Kaixo.blink(param,time);
			}
		});
		
		xmitDelay2 = Time.toTickSpan(Time.SECONDS, 1);
		timerLEds.setAlarmBySpan(xmitDelay2);
		
	}
	
	public static void allLedsOff (byte param, long time) {
        // turn-off all LEDs
        for (byte i=0; i<numLeds; i++)
            LED.setState(i, (byte)0);
    }

 
    public static void blink (byte param, long time) {
    	LED.setState((byte)0, ledAmarillo);
    	LED.setState((byte)1, ledVerde);
    	LED.setState((byte)2, ledRojo);
    	
        timerLEds.setAlarmBySpan(xmitDelay2);
    }
	
	// comprobar conexion pendientes
	public static void comprobarConexiones(){
		for(int i=0;i<estadoConexion.length;i++){
			
		}
	}
	
	
	//Si un paquete no es para le nodo redirigelo.
	public static void redirigir(byte[] pdu,int len) {
		int rNork = (int)pdu[8];
		int rNora = (int)pdu[9];
		int rNundik = (int)pdu[10];
		//aldatu bidea
		xmit[10] =(byte)nundik[rNora];
		//birbidali mezua
		Radio.transmit(Radio.TXMODE_POWER_MAX, xmit, 0, 12, onDone);
		
	}

	// On a received pdu turn on the appropriate LEDs based on sequence number
	public static void onRxPDU (byte[] pdu, int len, long time, int quality) {
		conection.introducirPaqueteRecivido(pdu,pak);
		if ((pdu[9] != idsId)&&(pdu[8] != idsId)&&(conozcoRuta((int)pdu[9]))&&(pdu[10]==idsId)){
			redirigir(pdu, len);
			return;
		}else if(pdu[9] == idsId){
			paqueteRecivido(pdu,len,time,quality);			
		}else{

		}  
	}
	
	public static void paqueteRecivido(byte[] pdu, int len, long time, int quality){
		int idEmisor = pdu[8];
		Nodo nodo = recuperarNodo(idEmisor);
		
		
		switch(pdu[11]){
		case 1:
			break;
		case 2:
			int reputacion = 8;
			enviarReputacion(pdu[8],pdu[12],reputacion);
			break;
		case 3:
			break;
		case 4:
			break;
		case 5:
			enviarACK(idEmisor);
			break;
		default:
			break;
		}
		
		if((pdu[11]==0)&&(nodo.isEsperandoACK()==true)){
			nodo.setEsperandoACK(false);
			nodo.sumarConexionesRealizadas(1);
		}else{
			/*
			if(pdu[11]==5){
				enviarACK(idEmisor);
				//enviar(idNodo,data);
				Nodo node = recuperarNodo(idEmisor);
				//conection.enviar(idNodo, data, node);
				//conection.enviar(2, (byte)3, node);
			}*/
		}
			
	}
	
	// We do not check the return code in this example
	public static void transmitDone(byte[] pdu, int len, int status, long txend){
		
		
	}
	
	private static void onTxDone(byte[] data, int len, int status, long txend) {
		
	}

	// Re-enable frame reception after reception timeout	
	public static void onRxTimeout (int info) {
		// Re-enable frame reception
		Radio.enableRx(Time.currentTicks()+0x7FFFFFFF);
	}
	
	//Recuperar Nodo
	public static Nodo recuperarNodo(int id){
		for(int i=0; i<red.length;i++){
			if (red[i]!=null){
				if (red[i].getId()==id) {
					return red[i];
				}
			}				
		}
		return new Nodo(0,0);
	}
	
	//funcion para enviar reputacion a un nodo
			public static void enviarReputacion(int idNodo, int idNodoReputacion,int reputacion){
				// prepare beacon frame with src addressing
				xmit = new byte[14];
				xmit[0] = Radio.FCF_BEACON;
				xmit[1] = Radio.FCA_SRC_SADDR;
				Util.set16le(xmit, 3, 0x22);
				Util.set16le(xmit, 5, 0x1234);
				
				//prepara cabecera para IDS
				xmit[8] = (byte)idsId; 
				xmit[9] = (byte)idNodo;
				xmit[10] = (byte)nundik[idNodo-1];
				xmit[11] = (byte)12;
				xmit[12] = (byte)idNodoReputacion;
				xmit[13] = (byte)reputacion;
				Radio.transmit(Radio.TXMODE_POWER_MAX, xmit, 0, 14, onDone);
				
			}
	
	//funcion para enviar datos a un nodo
	public static void enviar(int idNodo, byte info){
		// prepare beacon frame with src addressing
		xmit = new byte[13];
		xmit[0] = Radio.FCF_BEACON;
		xmit[1] = Radio.FCA_SRC_SADDR;
		Util.set16le(xmit, 3, 0x22);
		Util.set16le(xmit, 5, 0x1234);
		
		//recuperar nodo
		Nodo nod = recuperarNodo(idNodo);
		
		//prepara cabecera para IDS
		xmit[8] = (byte)idsId; 
		xmit[9] = (byte)idNodo;
		xmit[10] = (byte)nod.ruta;
		xmit[11] = (byte)5;
		xmit[12] = info;
		Radio.transmit(Radio.TXMODE_POWER_MAX, xmit, 0, 13, onDone);
		recuperarNodo(idNodo).setEsperandoACK(true);
		
	}
	
	//enviar ack
		public static void enviarACK(int idNodo){
			// prepare beacon frame with src addressing
			xmit = new byte[12];
			xmit[0] = Radio.FCF_BEACON;
			xmit[1] = Radio.FCA_SRC_SADDR;
			Util.set16le(xmit, 3, 0x22);
			Util.set16le(xmit, 5, 0x1234);
			
			//recuperar nodo
			Nodo nod = recuperarNodo(idNodo);
			
			//prepara cabecera para IDS
			xmit[8] = (byte)idsId; 
			xmit[9] = (byte)idNodo;
			xmit[10] = (byte)nod.ruta;
			xmit[11] = (byte)0;
			Radio.transmit(Radio.TXMODE_POWER_MAX, xmit, 0, 12, onDone);
		}
	
	//funcion para pedir informacion a un nodo
	public static void pedirInfo(int idNodo){
		// prepare beacon frame with src addressing
		xmit = new byte[12];
		xmit[0] = Radio.FCF_BEACON;
		xmit[1] = Radio.FCA_SRC_SADDR;
		Util.set16le(xmit, 3, 0x22);
		Util.set16le(xmit, 5, 0x1234);
						
		//prepara cabecera para IDS
		xmit[8] = (byte)idsId; 
		xmit[9] = (byte)idNodo;
		xmit[10] = (byte)nundik[idNodo-1];
		xmit[11] = (byte)1;
		Radio.transmit(Radio.TXMODE_POWER_MAX, xmit, 0, 12, onDone);
	}
	
	//funcion para pedir la reputacion a un nodo
	public static void pedirReputacion(int idNodo){
		// prepare beacon frame with src addressing
		xmit = new byte[12];
		xmit[0] = Radio.FCF_BEACON;
		xmit[1] = Radio.FCA_SRC_SADDR;
		Util.set16le(xmit, 3, 0x22);
		Util.set16le(xmit, 5, 0x1234);
								
		//prepara cabecera para IDS
		xmit[8] = (byte)idsId; 
		xmit[9] = (byte)idNodo;
		xmit[10] = (byte)nundik[idNodo-1];
		xmit[11] = (byte)2;
		Radio.transmit(Radio.TXMODE_POWER_MAX, xmit, 0, 12, onDone);
	}
	//funcion para pedir en broadcasta la reputacion acerca de un nodo
	public static void pedirReputacionTodos(int idNodo){
		// prepare beacon frame with src addressing
		xmit = new byte[12];
		xmit[0] = Radio.FCF_BEACON;
		xmit[1] = Radio.FCA_SRC_SADDR;
		Util.set16le(xmit, 3, 0x22);
		Util.set16le(xmit, 5, 0x1234);
								
		//prepara cabecera para IDS
		xmit[8] = (byte)idsId; 
		xmit[9] = (byte)idNodo;
		xmit[10] = (byte)nundik[idNodo-1];
		xmit[11] = (byte)3;
		Radio.transmit(Radio.TXMODE_POWER_MAX, xmit, 0, 12, onDone);
	}
	
	//pedir a los nodos que estan al lado la informacion acerca de los nodos que componen el vecindario.
	public static void pedirVecindario(int idNodo){
		// prepare beacon frame with src addressing
		xmit = new byte[13];
		xmit[0] = Radio.FCF_BEACON;
		xmit[1] = Radio.FCA_SRC_SADDR;
		Util.set16le(xmit, 3, 0x22);
		Util.set16le(xmit, 5, 0x1234);
								
		//prepara cabecera para IDS
		xmit[8] = (byte)idsId; 
		xmit[9] = (byte)0;
		xmit[10] = (byte)0;
		xmit[11] = (byte)4;
		xmit[12] = (byte)idNodo;
		Radio.transmit(Radio.TXMODE_POWER_MAX, xmit, 0, 13, onDone);
	}
	
	//buscar en tabla de enroutamiento si se encuntra la ruta de un nodo
	public static boolean conozcoRuta(int idNodo){
		
		for(int i=0;i<nora.length;i++){
			if(nora[i]==idNodo){
				return true;
			}
		}
		return false;
	}
	
	
	
	public static boolean flowEnviar(int idNodo, byte data){
		if(listo==true){
			//enviar(idNodo,data);
			Nodo node = recuperarNodo(2);
			//conection.enviar(idNodo, data, node);
			conection.enviar(2, data, node);
			if(ledVerde==0){
				ledVerde=1;
			} else{
				ledVerde=0;
			}
		} else {
			return false;
		}
		return true;
	}
	
	// Called on a timer alarm
	public static void periodicSend(byte param, long time) {
		
		
		
		//flowEnviar(3,(byte)i);
		
		//proba
		/*Paquete[] na = new Paquete[125];
		int i=0;
		while(true){
			na[i] = new Paquete(xmit);
			i++;
		}*/
		//LED.setState((byte)0, (byte)1);
		
		// send the message 
		//Radio.transmit(0, xmit, 1, galdera, 0, 1, onDone);
		//Radio.transmit(Radio.TXMODE_POWER_MAX, xmit, 0, 12, onDone);
		// Setup a new alarm
		
	}

}
